/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkHttpUtil.h"
#include "MkUtil/MkUtil.h"

CMkHttpUtil CMkHttpUtil::m_Instance;
CMkHttpUtil::CMkHttpUtil()
{
    m_MapCodeDesc[MkHttpStateContinue] = "Continue";
    m_MapCodeDesc[MkHttpStateSwitchProtocol] = "Switching Protocols";
    m_MapCodeDesc[MkHttpStateOk] = "OK";
    m_MapCodeDesc[MkHttpStateCreated] = "Created";
    m_MapCodeDesc[MkHttpStateAccpeted] = "Accepted";
    m_MapCodeDesc[MkHttpStateNonAuthoritative] = "Non - Authoritative Information";
    m_MapCodeDesc[MkHttpStateNoContent] = "No Content";
    m_MapCodeDesc[MkHttpStateResetContent] = "Reset Content";
    m_MapCodeDesc[MkHttpStatePartialContent] = "Partial Content";
    m_MapCodeDesc[MkHttpStateMultipleChoices] = "Multiple Choices";
    m_MapCodeDesc[MkHttpStateMovedPermanently] = "Moved Permanently";
    m_MapCodeDesc[MkHttpStateFound] = "Found";
    m_MapCodeDesc[MkHttpStateSeeOther] = "See Other";
    m_MapCodeDesc[MkHttpStateNotModified] = "Not Modified";
    m_MapCodeDesc[MkHttpStateUseProxy] = "Use Proxy";
    m_MapCodeDesc[MkHttpStateTemporaryRedirect] = "Temporary Redirect";
    m_MapCodeDesc[MkHttpStateBadRequest] = "Bad Request";
    m_MapCodeDesc[MkHttpStateUnauthorized] = "Unauthorized";
    m_MapCodeDesc[MkHttpStatePaymentRequired] = "Payment Required";
    m_MapCodeDesc[MkHttpStateForbidden] = "Forbidden";
    m_MapCodeDesc[MkHttpStateNotFound] = "Not Found";
    m_MapCodeDesc[MkHttpStateMethodNotAllowed] = "Method Not Allowed";
    m_MapCodeDesc[MkHttpStateNotAcceptable] = "Not Acceptable";
    m_MapCodeDesc[MkHttpStateProxyAuthentication] = "Proxy Authentication Required";
    m_MapCodeDesc[MkHttpStateTimeout] = "Request Time - out";
    m_MapCodeDesc[MkHttpStateConflict] = "Conflict";
    m_MapCodeDesc[MkHttpStateGone] = "Gone";
    m_MapCodeDesc[MkHttpStateLengthRequired] = "Length Required";
    m_MapCodeDesc[MkHttpStatePreconditionFailed] = "Precondition Failed";
    m_MapCodeDesc[MkHttpStateEntityTooLarge] = "Request Entity Too Large";
    m_MapCodeDesc[MkHttpStateURITooLarge] = "Request - URI Too Large";
    m_MapCodeDesc[MkHttpStateUnsupportCodec] = "Unsupported Media Type";
    m_MapCodeDesc[MkHttpStateRangeNotSatisfiable] = "Requested range not satisfiable";
    m_MapCodeDesc[MkHttpStateExpectationFailed] = "Expectation Failed";
    m_MapCodeDesc[MkHttpStateInternalServerError] = "Internal Server Error";
    m_MapCodeDesc[MkHttpStateNotImplemented] = "Not Implemented";
    m_MapCodeDesc[MkHttpStateBadGateway] = "Bad Gateway";
    m_MapCodeDesc[MkHttpStateServiceUnavailable] = "Service Unavailable";
    m_MapCodeDesc[MkHttpStateGatewayTimeout] = "Gateway Time - out";
    m_MapCodeDesc[MkHttpStateVersionUnsupported] = "HTTP Version not supported";

    m_MapBodyType[MkHttpBodyTypeJson] = "application/json";
    m_MapBodyType[MkHttpBodyTypeXml] = "application/xml";
    m_MapBodyType[MkHttpBodyTypeText] = "text/xml";
    m_MapBodyType[MkHttpBodyTypePdf] = "application/pdf";
    m_MapBodyType[MkHttpBodyTypeForm] = "application/x-www-form-urlencoded";
    m_MapBodyType[MkHttpBodyTypeFormData] = "multipart/form-data";
    m_MapBodyType[MkHttpBodyTypeHtml] = "text/html";

    m_MapMethod[MkHttpMethodOptions] = "OPTIONS";
    m_MapMethod[MkHttpMethodGet] = "GET";
    m_MapMethod[MkHttpMethodHead] = "HEAD";
    m_MapMethod[MkHttpMethodPost] = "POST";
    m_MapMethod[MkHttpMethodPut] = "PUT";
    m_MapMethod[MkHttpMethodDelete] = "DELETE";
    m_MapMethod[MkHttpMethodTrace] = "TRACE";
    m_MapMethod[MkHttpMethodConnect] = "CONNECT";

    m_MapMkMethod["OPTIONS"] = MkHttpMethodOptions;
    m_MapMkMethod["GET"] = MkHttpMethodGet;
    m_MapMkMethod["HEAD"] = MkHttpMethodHead;
    m_MapMkMethod["POST"] = MkHttpMethodPost;
    m_MapMkMethod["PUT"] = MkHttpMethodPut;
    m_MapMkMethod["DELETE"] = MkHttpMethodDelete;
    m_MapMkMethod["TRACE"] = MkHttpMethodTrace;
    m_MapMkMethod["CONNECT"] = MkHttpMethodConnect;
}

const MkString& CMkHttpUtil::GetCodeDesc(const MkHttpStatusCode& StatusCode) const
{
    MkUnorderedMap<Uint32, MkString>::const_iterator it = m_MapCodeDesc.find(StatusCode);
    if (it != m_MapCodeDesc.end()) {
        return it->second;
    }
    return m_EmptyString;
}

const MkString& CMkHttpUtil::GetBodyTypeDesc(const MkHttpBodyType& BodyType) const
{
    MkUnorderedMap<Uint32, MkString>::const_iterator it = m_MapBodyType.find(BodyType);
    if (it != m_MapBodyType.end()) {
        return it->second;
    }
    return m_EmptyString;
}

MkHttpMethod CMkHttpUtil::GetMkHttpMethod(const MkString& Method) const
{
    MkUnorderedMap<MkString, MkHttpMethod>::const_iterator it = m_MapMkMethod.find(Method);
    if (it != m_MapMkMethod.end()) {
        return it->second;
    }
    return MkHttpMethodUnknown;
}

const MkString& CMkHttpUtil::GetMethod(const MkHttpMethod& Method) const
{
    MkUnorderedMap<Uint32, MkString>::const_iterator it = m_MapMethod.find(Method);
    if (it != m_MapMethod.end()) {
        return it->second;
    }
    return m_EmptyString;
}


Uint32 CMkHttpUtil::HttpUrlParse(const MkString &HttpUrl, MkString& Domain, MkString &Host, Uint16 &Port, MkString& Path)
{
    Uint32 ErrorCode = NoneError;
    if ("http://" == HttpUrl.substr(0, 7)) {
        MkString Tmp = HttpUrl.substr(7);
        size_t nfind = Tmp.find(":");
        size_t nfind1 = Tmp.find("/");
        if (MkString::npos == nfind || nfind > nfind1) { //not find :
            Port = 80;
            Domain = Tmp.substr(0, nfind1);
        } else {
            Domain = Tmp.substr(0, nfind);
            MkString strPort = Tmp.substr(nfind + 1, nfind1 - nfind - 1);
            Port = static_cast<Uint16>(std::stoi(strPort));
        }
        Path = MkString::npos == nfind1 ? "" : Tmp.substr(nfind1);
        ErrorCode = NoneError;
    } else if ("https://" == HttpUrl.substr(0, 8)) {
        MkString Tmp = HttpUrl.substr(8);
        size_t nfind = Tmp.find(":");
        size_t nfind1 = Tmp.find("/");
        if (MkString::npos == nfind) { //not find :
            Port = 443;
            Domain = Tmp.substr(0, nfind1);
        } else {
            Domain = Tmp.substr(0, nfind);
            MkString strPort = Tmp.substr(nfind + 1, nfind1 - nfind - 1);
            Port = static_cast<Uint16>(std::stoi(strPort));
        }
        Path = Tmp.substr(nfind1);
        ErrorCode = NoneError;
    } else {
        ErrorCode = InvalidUrl;
    }
    if (NoneError == ErrorCode) {
        CMkUtil::GetOneIpByHostName(Domain, Host);
    }
    return ErrorCode;
}

Uint32 CMkHttpUtil::WebsocketUrlParse(const MkString &HttpUrl, MkString& Domain, MkString &Host, Uint16 &Port, MkString& Path)
{
    Uint32 ErrorCode = NoneError;
    if ("ws://" == HttpUrl.substr(0, 5)) {
        MkString Tmp = HttpUrl.substr(5);
        size_t nfind = Tmp.find(":");
        size_t nfind1 = Tmp.find("/");
        if (MkString::npos == nfind || nfind > nfind1) { //not find :
            Port = 80;
            Domain = Tmp.substr(0, nfind1);
        } else {
            Domain = Tmp.substr(0, nfind);
            MkString strPort = Tmp.substr(nfind + 1, nfind1 - nfind - 1);
            Port = static_cast<Uint16>(std::stoi(strPort));
        }
        Path = Tmp.substr(nfind1);
        ErrorCode = NoneError;
    } else if ("wss://" == HttpUrl.substr(0, 6)) {
        MkString Tmp = HttpUrl.substr(6);
        size_t nfind = Tmp.find(":");
        size_t nfind1 = Tmp.find("/");
        if (MkString::npos == nfind) { //not find :
            Port = 443;
            Domain = Tmp.substr(0, nfind1);
        } else {
            Domain = Tmp.substr(0, nfind);
            MkString strPort = Tmp.substr(nfind + 1, nfind1 - nfind - 1);
            Port = static_cast<Uint16>(std::stoi(strPort));
        }
        Path = Tmp.substr(nfind1);
        ErrorCode = NoneError;
    } else {
        ErrorCode = InvalidUrl;
    }
    if (NoneError == ErrorCode) {
        CMkUtil::GetOneIpByHostName(Domain, Host);
    }
    return ErrorCode;
}

CMkHttpUtil::~CMkHttpUtil()
{

}



